programming4us
           
 
 
Programming

.NET Components : Serialization and Class Hierarchies (part 2) - Manual Base-Class Serialization

- Free product key for windows 10
- Free Product Key for Microsoft office 365
- Malwarebytes Premium 3.7.1 Serial Keys (LifeTime) 2019
6/30/2013 9:26:32 PM

2. Manual Base-Class Serialization

Combining class hierarchies and serialization, whether fully automatic or custom, is straightforward: all classes either use only the Serializable attribute, or use the attribute and also implement ISerializable. However, the picture isn't so clear when it comes to deriving a serializable class from a class not marked with the Serializable attribute, as in this case:

    public class MyBaseClass
    {}
    [Serializable]
    public class MySubClass : MyBaseClass
    {}

In fact, in such a case, .NET can't serialize objects of type MySubClass at all, because it can't serialize their base classes. Trying to serialize an object of type MySubClass results in an exception of type SerializationException. Such a situation may occur when deriving from a class in a third-party assembly where the vendor neglected to mark its class as serializable.

The good news is that there is a workaround for such a case. The solution presented here isn't a sure cure, because it assumes that none of the base classes require custom serialization steps. It merely compensates for the oversight of not marking the base class as serializable.

The workaround is simple: the subclass can implement ISerializable, use reflection to read and serialize the base classes' fields, and use reflection again to set these fields during deserialization. The static SerializationUtil helper class provides the two static methods SerializeBaseType( ) and DeserializeBaseType( ), defined as:

    public static class SerializationUtil
    {
       public static void SerializeBaseType(object obj,
                                            SerializationInfo info,
                                            StreamingContext context);
       public static void DeserializeBaseType(object obj,
                                              SerializationInfo info,
                                              StreamingContext context);
       //Rest of SerializationUtil
    }

All the subclass needs to do is implement ISerializable and use SerializationUtil to serialize and deserialize its base classes:

    public class MyBaseClass
    {}
    [Serializable]
    public class MySubClass : MyBaseClass,ISerializable
    {
       public MySubClass(  )
       {}
       public void GetObjectData(SerializationInfo info,StreamingContext context)
       {
          SerializationUtil.SerializeBaseType(this,info,context);
       }
       protected MySubClass(SerializationInfo info,StreamingContext context)
       {
          SerializationUtil.DeserializeBaseType(this,info,context);
       }
    }

					  

If the subclass itself has no need for custom serialization and only implements ISerializable to serialize its base class, you can use SerializationUtil to serialize the subclass as well. SerializationUtil provides these overloaded versions of SerializeBaseType( ) and DeserializeBaseType( ):

    public static void SerializeBaseType(object obj,bool
					serializeSelf,
                                         SerializationInfo info,
                                         StreamingContext context);
    public static void DeserializeBaseType(object obj,bool
					deserializeSelf,
                                           SerializationInfo info,
                                           StreamingContext context);

These versions accept a flag instructing them whether to start serialization with the type itself instead of its base class:

    public void GetObjectData(SerializationInfo info,StreamingContext context)
    {
       //Serializing this type and its base classes
       SerializationUtil.SerializeBaseType(this,true,info,context);
    }
    protected MyClass(SerializationInfo info,StreamingContext context)
    {
       //Deserializing this type and its base classes
       SerializationUtil.DeserializeBaseType(this,true,info,context);
    }

					  

SerializationUtil is also useful in cases where a class needs to provide custom serialization, even though simple use of the Serializable attribute would have sufficed for that class. This may occur because, as mentioned previously, if any class in a class hierarchy provides custom serialization, all its subclasses must do so as well. It can also occur when a type is constrained to implement Iserializable, to be used as a generic type parameter in a generic class.


Example 2 demonstrates the implementations of SerializeBaseType and DeserializeBaseType.

Example 2. Implementing SerializeBaseType and DeserializeBaseType
public static class SerializationUtil
{
   public static void SerializeBaseType(object obj,
                                   SerializationInfo info,StreamingContext context)
   {
      Type baseType = obj.GetType(  ).BaseType;
      SerializeBaseType(obj,baseType,info,context);
   }
   static void SerializeBaseType(object obj,Type type,SerializationInfo info,
                                                          StreamingContext context)
   {
      if(type == typeof(object))
      {
         return;
      }
      BindingFlags flags = BindingFlags.Instance|BindingFlags.DeclaredOnly|
                           BindingFlags.NonPublic|BindingFlags.Public;
      FieldInfo[] fields = type.GetFields(flags);
      foreach(FieldInfo field in fields)
      {
         if(field.IsNotSerialized)
         {
            continue;
         }
         string fieldName = type.Name + "+" + field.Name;

         info.AddValue(fieldName,field.GetValue(obj));
      }
      SerializeBaseType(obj,type.BaseType,info,context);
   }
   public static void DeserializeBaseType(object obj,SerializationInfo info,
                                                          StreamingContext context)
   {
      Type baseType = obj.GetType(  ).BaseType;
      DeserializeBaseType(obj,baseType,info,context);
   }
   static void DeserializeBaseType(object obj,Type type,SerializationInfo info,
                                                          StreamingContext context)
   {
      if(type == typeof(object))
      {
         return;
      }
      BindingFlags flags = BindingFlags.Instance|BindingFlags.DeclaredOnly|
                           BindingFlags.NonPublic|BindingFlags.Public;
      FieldInfo[] fields = type.GetFields(flags);
      foreach(FieldInfo field in fields)
      {
         if(field.IsNotSerialized)
         {
            continue;
         }
         string fieldName = type.Name + "+" + field.Name;
         object fieldValue = info.GetValue(fieldName,field.FieldType);
         field.SetValue(obj,fieldValue);
      }
      DeserializeBaseType(obj,type.BaseType,info,context);
   }
   //Rest of SerializationUtil
}

					  

When SerializationUtil serializes an object's base class, it needs to serialize all the base classes leading to that base class as well. You can access the base-class type using the BaseType property of Type:

    Type baseType = obj.GetType(  ).BaseType;

With the GetFields( ) method of Type, you can get all the fields (private and public) declared by the type, as well as any public or protected fields available via its own base classes. This isn't good enough for serialization, though, because you need to capture all the private fields available from all levels of the class hierarchy, including ones with the same name. The solution is to serialize each level of the class hierarchy separately and thus access each level's private fields. SerializeBaseType( ) calls a private helper method, also called SerializeBaseType( ), providing it with the level of the class hierarchy to serialize:

    SerializeBaseType(obj,baseType,info,context);

The private SerializeBaseType( ) serializes that level and then calls itself recursively, serializing the next level up the hierarchy:

    SerializeBaseType(obj,type.BaseType,info,context);

The recursion stops once it reaches the System.Object level:

    static void SerializeBaseType(object obj,Type type,SerializationInfo info,
                                  StreamingContext context)
    {
       if(type == typeof(object))
       {
          return;
       }
       /* Rest of the implementation */
    }

					  

To serialize a particular level, the private SerializeBaseType( ) calls GetFields( ) with a binding flags mask (BindingFlags.DeclaredOnly), which instructs it to return all fields defined by this type only and not its base types. This ensures that as it visits the next levels up the hierarchy, it doesn't end up serializing fields more than once. It also binds to instance and not static fields, because static fields are never serialized:

    BindingFlags flags = BindingFlags.Instance|BindingFlags.DeclaredOnly|
                         BindingFlags.NonPublic|BindingFlags.Public;

The private SerializeBaseType( ) then calls GetFields( ) and stores the result in an array of FieldInfo objects:

    FieldInfo[] fields = type.GetFields(flags);

This solution needs to deal with a class hierarchy in which some levels actually use the Serializable attribute, such as class A in this example:

    [Serializable]
    class A
    {}
    class B : A
    {}
    [Serializable]
    class C : B,ISerializable
    {...}

Because class A may contain some fields marked with the NonSerialized attribute, the solution needs to check that the fields are serializable. This is easy to do via the IsNotSerialized Boolean property of FieldInfo:

    foreach(FieldInfo field in fields)
    {
       if(field.IsNotSerialized)
       {
          continue;
       }
       //Rest of the iteration loop
    }

Since different levels can declare private fields with the same names in the same class hierarchy, the private SerializeBaseType( ) prefixes each field name with its declaring type separated by a +:

    string fieldName = type.Name + "+" + field.Name;

The value of a field is obtained via the GetValue( ) method of FieldInfo and is then added to the info parameter:

    info.AddValue(fieldName,field.GetValue(obj));

Deserialization of the base class (or classes) is similar to serialization and is also done recursively until the System.Object level is reached. The public DeserializeBaseType( ) method accesses the base type and calls the private helper method DeserializeBaseType( ). At each level in the class hierarchy, the private DeserializeBaseType( ) retrieves the collection of fields for that type. For each field, it creates a name by appending the name of the current level to the name of the field, gets the value from info, and sets the value of the corresponding field, using the SetValue( ) method of the FieldInfo class:

    string fieldName = type.Name + "+" + field.Name;
    object fieldValue =
    info.GetValue(fieldName,field.FieldType);field.SetValue(obj,fieldValue);

					  
Other -----------------
- .NET Components : Custom Serialization (part 2) - Constraining Serialization
- .NET Components : Custom Serialization (part 1) - The ISerializable Interface, Implementing ISerializable
- .NET Components : Serialization and Streams - Serializing Multiple Objects
- Microsoft ASP.NET 3.5 : Writing HTTP Handlers (part 5) - Advanced HTTP Handler Programming
- Microsoft ASP.NET 3.5 : Writing HTTP Handlers (part 4) - Serving Images More Effectively
- Microsoft ASP.NET 3.5 : Writing HTTP Handlers (part 3) - The Picture Viewer Handler
- Microsoft ASP.NET 3.5 : Writing HTTP Handlers (part 2) - An HTTP Handler for Quick Data Reports
- Microsoft ASP.NET 3.5 : Writing HTTP Handlers (part 1) - The IHttpHandler Interface
- Microsoft ASP.NET 3.5 : HTTP Handlers and Modules - Quick Overview of the IIS Extensibility API
- Programming WCF Services : Queued Services - The HTTP Bridge
- Microsoft ASP.NET 4 : Ajax - Extender Controls (part 2) - A Modal Pop-up Dialog-Style Component
- Microsoft ASP.NET 4 : Ajax - Extender Controls (part 1) - The AutoComplete Extender
- Mobile Handheld Devices : DATA SYNCHRONIZATION
- Mobile Handheld Devices : MEMORY, STORAGE AND BATTERIES
- LINQ to Objects : How to Return Elements When the Result Is a Sequence (Select Many)
- LINQ to Objects : How to Change the Return Type (Select Projection)
- A Technical Overview of the Mobile Web : OTHER MOBILE TECHNOLOGIES
- A Technical Overview of the Mobile Web : THE MOBILE NETWORK
- Programming WCF Services : The Response Service (part 4) - Transactions
- Programming WCF Services : The Response Service (part 3) - Queued Service-Side Programming & Response Service-Side Programming
 
 
 
Top 10
 
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
- Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
- Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
- First look: Apple Watch

- 3 Tips for Maintaining Your Cell Phone Battery (part 1)

- 3 Tips for Maintaining Your Cell Phone Battery (part 2)
programming4us programming4us